package lightObjects;

import java.util.ArrayList;
import java.util.List;

import utils.ColorRGB;
import utils.GeoUtils;
import utils.Point3D;
import utils.Ray;
import utils.Vector;
import main.Parseable;
import main.Parser;
import main.Parser.ParseException;

public class AreaLight implements lightObject, Parseable {

    private ColorRGB color;
    private Point3D p0, p1, p2;
    private int gridWidth;

    private List<lightObject> pointLights;

    public AreaLight() {
	this.color = new ColorRGB(1, 1, 1);

	pointLights = new ArrayList<lightObject>();
    }

    public boolean setParameter(String name, String[] args) throws ParseException {
	if (name.equals("color")) {
	    if (args.length != 3) {
		System.out.println("bad parameters");
		return false;
	    }
	    color = new ColorRGB(Parser.stringArrToDoubleArr(args));
	    return true;
	} else if (name.equals("p0")) {
	    if (args.length != 3) {
		System.out.println("bad parameters");
		return false;
	    }
	    p0 = new Point3D(Parser.stringArrToDoubleArr(args));
	    return true;
	} else if (name.equals("p1")) {
	    if (args.length != 3) {
		System.out.println("bad parameters");
		return false;
	    }
	    p1 = new Point3D(Parser.stringArrToDoubleArr(args));
	    return true;
	} else if (name.equals("p2")) {
	    if (args.length != 3) {
		System.out.println("bad parameters");
		return false;
	    }
	    p2 = new Point3D(Parser.stringArrToDoubleArr(args));
	    return true;
	} else if (name.equals("grid-width")) {
	    if (args.length != 1) {
		System.out.println("bad parameters");
		return false;
	    }
	    gridWidth = (int) Double.parseDouble(args[0]);
	    return true;
	}

	// We didn't find any parameter
	return false;
    }

    public boolean finalizeObject() {
	if (p0 == null || p1 == null || p2 == null || gridWidth <= 0) {
	    System.out.println("Error: one or more parameters are missing");
	    return false;
	}

	// Check that the 3 points aren't colinear
	if (GeoUtils.isCollinear(p0, p1, p2)) {
	    System.out.println("Error: Area light points are colinear");
	    return false;
	}

	Vector v0 = new Vector(p0, p1);
	Vector v1 = new Vector(p0, p2);

	Point3D curPos;

	double initMove = ((double) 1 / (double) gridWidth) / 2;
	Point3D initPos = p0.addVector(v0.scale(initMove));
	initPos = initPos.addVector(v1.scale(initMove));

	for (int i = 0; i < gridWidth; i++) {
	    curPos = initPos.addVector(v0.scale((double) i / (double) gridWidth));
	    for (int j = 0; j < gridWidth; j++) {
		curPos = curPos.addVector(v1.scale((double) 1.0 / (double) gridWidth));

		pointLights.add(new PointLight(color.multiply(1.0 / (gridWidth * gridWidth)), curPos));
	    }
	}

	return true;
    }

    @Override
    public boolean isCamera() {
	return false;
    }

    public boolean isLight() {
	return true;
    }

    @Override
    public List<lightObject> getLightSources() {
	return pointLights;
    }

    // Those function will never be called, as this object returns other light objects
    @Override
    public Ray buildRayFrom(Point3D p) {
	return null;
    }

    @Override
    public ColorRGB getIllumination(Point3D p) {
	return null;
    }

    public double getDistanceFromPoint(Point3D p) {
	return 0;
    }
}
